home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / mig / dist / routine.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-01-28  |  38.5 KB  |  1,457 lines

  1. /* 
  2.  * Mach Operating System
  3.  * Copyright (c) 1991,1990 Carnegie Mellon University
  4.  * All Rights Reserved.
  5.  * 
  6.  * Permission to use, copy, modify and distribute this software and its
  7.  * documentation is hereby granted, provided that both the copyright
  8.  * notice and this permission notice appear in all copies of the
  9.  * software, derivative works or modified versions, and any portions
  10.  * thereof, and that both notices appear in supporting documentation.
  11.  * 
  12.  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  13.  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  14.  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  15.  * 
  16.  * Carnegie Mellon requests users of this software to return to
  17.  * 
  18.  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
  19.  *  School of Computer Science
  20.  *  Carnegie Mellon University
  21.  *  Pittsburgh PA 15213-3890
  22.  * 
  23.  * any improvements or extensions that they make and grant Carnegie Mellon
  24.  * the rights to redistribute these changes.
  25.  */
  26. /*
  27.  * HISTORY
  28.  * $Log:    routine.c,v $
  29.  * Revision 2.8  92/01/14  16:46:28  rpd
  30.  *     Added itCheckFlags, itCheckDeallocate,
  31.  *     itCheckIsLong, itCheckServerCopy.
  32.  *     Revised the CountInOut implementation.
  33.  *     Modified deallocate bit implementation for Indefinite types.
  34.  *     [92/01/09            rpd]
  35.  * 
  36.  * Revision 2.7  92/01/03  20:29:39  dbg
  37.  *     Indefinite OUT arrays are passed by pointer, not by address.
  38.  * 
  39.  *     Set argByReferenceUser and argByReferenceServer fields.
  40.  *     [91/09/04            dbg]
  41.  * 
  42.  * Revision 2.6  91/08/28  11:17:12  jsb
  43.  *     Removed Camelot and TrapRoutine support.
  44.  *     Changed MsgKind to MsgSeqno.
  45.  *     [91/08/12            rpd]
  46.  * 
  47.  * Revision 2.5  91/07/31  18:10:15  dbg
  48.  *     Support indefinite-length (inline or out-of-line) variable
  49.  *     arrays.
  50.  *     [91/04/10            dbg]
  51.  * 
  52.  *     Change argDeallocate to an enumerated type, to allow for
  53.  *     user-specified deallocate flag.
  54.  * 
  55.  *     Special handling for varying C_Strings in rtAddCountArg.
  56.  * 
  57.  *     Add rtCheckMaskFunction.  Add rtNoReplyArgs to routine
  58.  *     structure.
  59.  *     [91/04/03            dbg]
  60.  * 
  61.  * Revision 2.4  91/02/05  17:55:20  mrt
  62.  *     Changed to new Mach copyright
  63.  *     [91/02/01  17:55:07  mrt]
  64.  * 
  65.  * Revision 2.3  90/09/28  16:57:29  jsb
  66.  *     Fixed bug setting akbRequestQC in rtAugmentArgKind.
  67.  *     Kernel servers can't quick-check the deallocate bit
  68.  *     on port arguments.
  69.  *     [90/09/19            rpd]
  70.  * 
  71.  * Revision 2.2  90/06/02  15:05:17  rpd
  72.  *     Created for new IPC.
  73.  *     [90/03/26  21:12:43  rpd]
  74.  * 
  75.  * 07-Apr-89  Richard Draves (rpd) at Carnegie-Mellon University
  76.  *    Extensive revamping.  Added polymorphic arguments.
  77.  *    Allow multiple variable-sized inline arguments in messages.
  78.  *
  79.  * 17-Oct-88  Mary Thompson (mrt) at Carnegie-Mellon University
  80.  *    Added to code to rtAugmentArgKind to reject any inline
  81.  *    variable arguments that are both In and Out.
  82.  *
  83.  * 27-Feb-88  Richard Draves (rpd) at Carnegie-Mellon University
  84.  *    Added warning messages.  CamelotRoutines should only be
  85.  *    used in camelot subsystems, which should consist entirely
  86.  *    of CamelotRoutines.
  87.  *
  88.  * 18-Feb-88  Richard Draves (rpd) at Carnegie-Mellon University
  89.  *    Fix to rtCheckRoutineArgs, so we don't seg-fault on bad input.
  90.  *    We want to do some checking for malformed args after an error,
  91.  *    but nothing that has to use their type (which is NULL).
  92.  *
  93.  * 20-Dec-87  David Golub (dbg) at Carnegie-Mellon University
  94.  *    Fill in pointers to last request and reply arguments.  Implement
  95.  *    partial variable-length messages - only the last inline argument
  96.  *    in a message can vary in size.  Added argMultiplier field for
  97.  *    count arguments.
  98.  *
  99.  * 16-Nov-87  David Golub (dbg) at Carnegie-Mellon University
  100.  *    Don't add akbVarNeeded attribute here - server.c can
  101.  *    better determine whether it is needed.
  102.  *
  103.  * 25-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
  104.  *    Changed CamelotPrefix from a UserPrefix to a ServerPrefix.
  105.  *
  106.  * 18-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
  107.  *    Added code to add requestPort, Tid and WaitTime 
  108.  *    arguments for CamelotRoutines.
  109.  *
  110.  * 10-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
  111.  *    Added code to handle MsgType arguments
  112.  *
  113.  * 15-Jun-87  David Black (dlb) at Carnegie-Mellon University
  114.  *    Fixed rtAlloc and argAlloc to correctly initialize string
  115.  *    pointers in allocated structures.
  116.  *
  117.  * 28-May-87  Richard Draves (rpd) at Carnegie-Mellon University
  118.  *    Created.
  119.  */
  120.  
  121. /*
  122.  *  ABSTRACT:
  123.  *   Provides the routine used by parser.c to generate
  124.  *   routine structures for each routine statement.
  125.  *   The parser generates a threaded list of statements
  126.  *   of which the most interesting are the various kinds
  127.  *   routine statments. The routine structure is defined
  128.  *   in routine.h which includes it name, kind of routine
  129.  *   and other information,
  130.  *   a pointer to an argument list which contains the name
  131.  *   and type information for each argument, and a list
  132.  *   of distinguished arguments, eg.  Request and Reply
  133.  *   ports, waittime, retcode etc.
  134.  */
  135.  
  136. #include <mach/message.h>
  137. #include "error.h"
  138. #include "alloc.h"
  139. #include "global.h"
  140. #include "routine.h"
  141.  
  142. u_int rtNumber = 0;
  143.  
  144. routine_t *
  145. rtAlloc()
  146. {
  147.     register routine_t *new;
  148.  
  149.     new = (routine_t *) calloc(1, sizeof *new);
  150.     if (new == rtNULL)
  151.     fatal("rtAlloc(): %s", unix_error_string(errno));
  152.     new->rtNumber = rtNumber++;
  153.     new->rtName = strNULL;
  154.     new->rtErrorName = strNULL;
  155.     new->rtUserName = strNULL;
  156.     new->rtServerName = strNULL;
  157.  
  158.     return new;
  159. }
  160.  
  161. void
  162. rtSkip()
  163. {
  164.     rtNumber++;
  165. }
  166.  
  167. argument_t *
  168. argAlloc()
  169. {
  170.     static argument_t prototype =
  171.     {
  172.     strNULL,        /* identifier_t argName */
  173.     argNULL,        /* argument_t *argNext */
  174.     akNone,            /* arg_kind_t argKind */
  175.     itNULL,            /* ipc_type_t *argType */
  176.     strNULL,        /* string_t argVarName */
  177.     strNULL,        /* string_t argMsgField */
  178.     strNULL,        /* string_t argTTName */
  179.     strNULL,        /* string_t argPadName */
  180.     flNone,            /* ipc_flags_t argFlags */
  181.     d_NO,            /* dealloc_t argDeallocate */
  182.     FALSE,            /* boolean_t argLongForm */
  183.     FALSE,            /* boolean_t argServerCopy */
  184.     FALSE,            /* boolean_t argCountInOut */
  185.     rtNULL,            /* routine_t *argRoutine */
  186.     argNULL,        /* argument_t *argCount */
  187.     argNULL,        /* argument_t *argCInOut */
  188.     argNULL,        /* argument_t *argPoly */
  189.     argNULL,        /* argument_t *argDealloc */
  190.     argNULL,        /* argument_t *argSCopy */
  191.     argNULL,        /* argument_t *argParent */
  192.     1,            /* int argMultiplier */
  193.     0,            /* int argRequestPos */
  194.     0,            /* int argReplyPos */
  195.     FALSE,            /* boolean_t argByReferenceUser */
  196.     FALSE            /* boolean_t argByReferenceServer */
  197.     };
  198.     register argument_t *new;
  199.  
  200.     new = (argument_t *) malloc(sizeof *new);
  201.     if (new == argNULL)
  202.     fatal("argAlloc(): %s", unix_error_string(errno));
  203.     *new = prototype;
  204.     return new;
  205. }
  206.  
  207. routine_t *
  208. rtMakeRoutine(name, args)
  209.     identifier_t name;
  210.     argument_t *args;
  211. {
  212.     register routine_t *rt = rtAlloc();
  213.  
  214.     rt->rtName = name;
  215.     rt->rtKind = rkRoutine;
  216.     rt->rtArgs = args;
  217.  
  218.     return rt;
  219. }
  220.  
  221. routine_t *
  222. rtMakeSimpleRoutine(name, args)
  223.     identifier_t name;
  224.     argument_t *args;
  225. {
  226.     register routine_t *rt = rtAlloc();
  227.  
  228.     rt->rtName = name;
  229.     rt->rtKind = rkSimpleRoutine;
  230.     rt->rtArgs = args;
  231.  
  232.     return rt;
  233. }
  234.  
  235. routine_t *
  236. rtMakeProcedure(name, args)
  237.     identifier_t name;
  238.     argument_t *args;
  239. {
  240.     register routine_t *rt = rtAlloc();
  241.  
  242.     rt->rtName = name;
  243.     rt->rtKind = rkProcedure;
  244.     rt->rtArgs = args;
  245.  
  246.     warn("Procedure %s: obsolete routine kind", name);
  247.  
  248.     return rt;
  249. }
  250.  
  251. routine_t *
  252. rtMakeSimpleProcedure(name, args)
  253.     identifier_t name;
  254.     argument_t *args;
  255. {
  256.     register routine_t *rt = rtAlloc();
  257.  
  258.     rt->rtName = name;
  259.     rt->rtKind = rkSimpleProcedure;
  260.     rt->rtArgs = args;
  261.  
  262.     warn("SimpleProcedure %s: obsolete routine kind", name);
  263.  
  264.     return rt;
  265. }
  266.  
  267. routine_t *
  268. rtMakeFunction(name, args, type)
  269.     identifier_t name;
  270.     argument_t *args;
  271.     ipc_type_t *type;
  272. {
  273.     register routine_t *rt = rtAlloc();
  274.     register argument_t *ret = argAlloc();
  275.  
  276.     ret->argName = name;
  277.     ret->argKind = akReturn;
  278.     ret->argType = type;
  279.     ret->argNext = args;
  280.  
  281.     rt->rtName = name;
  282.     rt->rtKind = rkFunction;
  283.     rt->rtArgs = ret;
  284.  
  285.     warn("Function %s: obsolete routine kind", name);
  286.  
  287.     return rt;
  288. }
  289.  
  290. char *
  291. rtRoutineKindToStr(rk)
  292.     routine_kind_t rk;
  293. {
  294.     switch (rk)
  295.     {
  296.       case rkRoutine:
  297.     return "Routine";
  298.       case rkSimpleRoutine:
  299.     return "SimpleRoutine";
  300.       case rkProcedure:
  301.     return "Procedure";
  302.       case rkSimpleProcedure:
  303.     return "SimpleProcedure";
  304.       case rkFunction:
  305.     return "Function";
  306.       default:
  307.     fatal("rtRoutineKindToStr(%d): not a routine_kind_t", rk);
  308.     /*NOTREACHED*/
  309.     }
  310. }
  311.  
  312. static void
  313. rtPrintArg(arg)
  314.     register argument_t *arg;
  315. {
  316.     register ipc_type_t *it = arg->argType;
  317.  
  318.     if (!akCheck(arg->argKind, akbUserArg|akbServerArg) ||
  319.     (akIdent(arg->argKind) == akeCount) ||
  320.     (akIdent(arg->argKind) == akePoly))
  321.     return;
  322.  
  323.     printf("\n\t");
  324.  
  325.     switch (akIdent(arg->argKind))
  326.     {
  327.       case akeRequestPort:
  328.     printf("RequestPort");
  329.     break;
  330.       case akeReplyPort:
  331.     printf("ReplyPort");
  332.     break;
  333.       case akeWaitTime:
  334.     printf("WaitTime");
  335.     break;
  336.       case akeMsgOption:
  337.     printf("MsgOption");
  338.     break;
  339.       case akeMsgSeqno:
  340.     printf("MsgSeqno\t");
  341.     break;
  342.       default:
  343.     if (akCheck(arg->argKind, akbRequest))
  344.         if (akCheck(arg->argKind, akbSend))
  345.         printf("In");
  346.         else
  347.         printf("(In)");
  348.     if (akCheck(arg->argKind, akbReply))
  349.         if (akCheck(arg->argKind, akbReturn))
  350.         printf("Out");
  351.         else
  352.         printf("(Out)");
  353.     printf("\t");
  354.     }
  355.  
  356.     printf("\t%s: %s", arg->argName, it->itName);
  357.  
  358.     if (arg->argDeallocate != it->itDeallocate)
  359.     if (arg->argDeallocate == d_YES)
  360.         printf(", Dealloc");
  361.     else if (arg->argDeallocate == d_MAYBE)
  362.         printf(", Dealloc[]");
  363.     else
  364.         printf(", NotDealloc");
  365.  
  366.     if (arg->argLongForm != it->itLongForm)
  367.     if (arg->argLongForm)
  368.         printf(", IsLong");
  369.     else
  370.         printf(", IsNotLong");
  371.  
  372.     if (arg->argServerCopy)
  373.     printf(", ServerCopy");
  374.  
  375.     if (arg->argCountInOut)
  376.     printf(", CountInOut");
  377. }
  378.  
  379. void
  380. rtPrintRoutine(rt)
  381.     register routine_t *rt;
  382. {
  383.     register argument_t *arg;
  384.  
  385.     printf("%s (%d) %s(", rtRoutineKindToStr(rt->rtKind),
  386.        rt->rtNumber, rt->rtName);
  387.  
  388.     for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
  389.     rtPrintArg(arg);
  390.  
  391.     if (rt->rtKind == rkFunction)
  392.     printf("): %s\n", rt->rtReturn->argType->itName);
  393.     else
  394.     printf(")\n");
  395.  
  396.     printf("\n");
  397. }
  398.  
  399. /*
  400.  * Determines appropriate value of msg-simple for the message,
  401.  * and whether this value can vary at runtime.  (If it can vary,
  402.  * then the simple value is optimistically returned as TRUE.)
  403.  * Uses itInName values, so useful when sending messages.
  404.  */
  405.  
  406. static void
  407. rtCheckSimpleIn(args, mask, fixed, simple)
  408.     argument_t *args;
  409.     u_int mask;
  410.     boolean_t *fixed, *simple;
  411. {
  412.     register argument_t *arg;
  413.     boolean_t MayBeComplex = FALSE;
  414.     boolean_t MustBeComplex = FALSE;
  415.  
  416.     for (arg = args; arg != argNULL; arg = arg->argNext)
  417.     if (akCheck(arg->argKind, mask))
  418.     {
  419.         register ipc_type_t *it = arg->argType;
  420.  
  421.         if (it->itInName == MACH_MSG_TYPE_POLYMORPHIC)
  422.         MayBeComplex = TRUE;
  423.  
  424.         if (it->itIndefinite)
  425.         MayBeComplex = TRUE;
  426.  
  427.         if (MACH_MSG_TYPE_PORT_ANY(it->itInName) ||
  428.         !it->itInLine)
  429.         MustBeComplex = TRUE;
  430.     }
  431.  
  432.     *fixed = MustBeComplex || !MayBeComplex;
  433.     *simple = !MustBeComplex;
  434. }
  435.  
  436. /*
  437.  * Determines appropriate value of msg-simple for the message,
  438.  * and whether this value can vary at runtime.  (If it can vary,
  439.  * then the simple value is optimistically returned as TRUE.)
  440.  * Uses itOutName values, so useful when receiving messages
  441.  * (and sending reply messages in KernelServer interfaces).
  442.  */
  443.  
  444. static void
  445. rtCheckSimpleOut(args, mask, fixed, simple)
  446.     argument_t *args;
  447.     u_int mask;
  448.     boolean_t *fixed, *simple;
  449. {
  450.     register argument_t *arg;
  451.     boolean_t MayBeComplex = FALSE;
  452.     boolean_t MustBeComplex = FALSE;
  453.  
  454.     for (arg = args; arg != argNULL; arg = arg->argNext)
  455.     if (akCheck(arg->argKind, mask))
  456.     {
  457.         register ipc_type_t *it = arg->argType;
  458.  
  459.         if (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)
  460.         MayBeComplex = TRUE;
  461.  
  462.         if (it->itIndefinite)
  463.         MayBeComplex = TRUE;
  464.  
  465.         if (MACH_MSG_TYPE_PORT_ANY(it->itOutName) ||
  466.         !it->itInLine)
  467.         MustBeComplex = TRUE;
  468.     }
  469.  
  470.     *fixed = MustBeComplex || !MayBeComplex;
  471.     *simple = !MustBeComplex;
  472. }
  473.  
  474. static u_int
  475. rtFindSize(args, mask)
  476.     argument_t *args;
  477.     u_int mask;
  478. {
  479.     register argument_t *arg;
  480.     u_int size = sizeof(mach_msg_header_t);
  481.  
  482.     for (arg = args; arg != argNULL; arg = arg->argNext)
  483.     if (akCheck(arg->argKind, mask))
  484.     {
  485.         register ipc_type_t *it = arg->argType;
  486.  
  487.         if (arg->argLongForm)
  488.         size += sizeof(mach_msg_type_long_t);
  489.         else
  490.         size += sizeof(mach_msg_type_t);
  491.  
  492.         size += it->itMinTypeSize;
  493.     }
  494.  
  495.     return size;
  496. }
  497.  
  498. boolean_t
  499. rtCheckMask(args, mask)
  500.     argument_t *args;
  501.     u_int mask;
  502. {
  503.     register argument_t *arg;
  504.  
  505.     for (arg = args; arg != argNULL; arg = arg->argNext)
  506.     if (akCheckAll(arg->argKind, mask))
  507.         return TRUE;
  508.     return FALSE;
  509. }
  510.  
  511. boolean_t
  512. rtCheckMaskFunction(args, mask, func)
  513.     argument_t *args;
  514.     u_int mask;
  515.     boolean_t (*func)(/* argument_t *arg */);
  516. {
  517.     register argument_t *arg;
  518.  
  519.     for (arg = args; arg != argNULL; arg = arg->argNext)
  520.     if (akCheckAll(arg->argKind, mask))
  521.         if ((*func)(arg))
  522.         return TRUE;
  523.     return FALSE;
  524. }
  525.  
  526. int
  527. rtCountMask(args, mask)
  528.     argument_t *args;
  529.     u_int mask;
  530. {
  531.     register argument_t *arg;
  532.     int count = 0;
  533.  
  534.     for (arg = args; arg != argNULL; arg = arg->argNext)
  535.     if (akCheckAll(arg->argKind, mask))
  536.         count++;
  537.     return count;
  538. }
  539.  
  540. /* arg->argType may be NULL in this function */
  541.  
  542. static void
  543. rtDefaultArgKind(rt, arg)
  544.     routine_t *rt;
  545.     argument_t *arg;
  546. {
  547.     if ((arg->argKind == akNone) &&
  548.     (rt->rtRequestPort == argNULL))
  549.     arg->argKind = akRequestPort;
  550.  
  551.     if (arg->argKind == akNone)
  552.     arg->argKind = akIn;
  553. }
  554.  
  555. /*
  556.  * Initializes arg->argDeallocate, arg->argLongForm,
  557.  * arg->argServerCopy, arg->argCountInOut from arg->argFlags.
  558.  */
  559.  
  560. static void
  561. rtProcessArgFlags(arg)
  562.     register argument_t *arg;
  563. {
  564.     register ipc_type_t *it = arg->argType;
  565.  
  566.     arg->argFlags = itCheckFlags(arg->argFlags, arg->argName);
  567.  
  568.     if (((IsKernelServer && akCheck(arg->argKind, akbReturn)) ||
  569.      (IsKernelUser && akCheck(arg->argKind, akbSend))) &&
  570.     (arg->argFlags & flDealloc) &&
  571.     (it->itDeallocate == d_NO)) {
  572.     /*
  573.      *    For a KernelServer interface and an Out argument,
  574.      *    or a KernelUser interface and an In argument,
  575.      *    we avoid a possible spurious warning about the deallocate bit.
  576.      *    For compatibility with Mach 2.5, the deallocate bit
  577.      *    may need to be enabled on some inline arguments.
  578.      */
  579.  
  580.     arg->argDeallocate = d_YES;
  581.     } else
  582.     arg->argDeallocate = itCheckDeallocate(it, arg->argFlags,
  583.                            it->itDeallocate, arg->argName);
  584.  
  585.     arg->argLongForm = itCheckIsLong(it, arg->argFlags,
  586.                      it->itLongForm, arg->argName);
  587.  
  588.     if (arg->argFlags & flServerCopy) {
  589.     if (it->itIndefinite && akCheck(arg->argKind, akbSend))
  590.         arg->argServerCopy = TRUE;
  591.     else
  592.         warn("%s: ServerCopy on argument is meaningless", arg->argName);
  593.     }
  594.  
  595.     if (arg->argFlags & flCountInOut) {
  596.     if (it->itVarArray && it->itInLine &&
  597.         akCheck(arg->argKind, akbReply))
  598.         arg->argCountInOut = TRUE;
  599.     else
  600.         warn("%s: CountInOut on argument is meaningless", arg->argName);
  601.     }
  602. }
  603.  
  604. static void
  605. rtAugmentArgKind(arg)
  606.     argument_t *arg;
  607. {
  608.     register ipc_type_t *it = arg->argType;
  609.  
  610.     /* akbVariable means variable-sized inline. */
  611.  
  612.     if (it->itVarArray && it->itInLine)
  613.     {
  614.     if (akCheckAll(arg->argKind, akbRequest|akbReply))
  615.         error("%s: Inline variable-sized arguments can't be InOut",
  616.           arg->argName);
  617.     arg->argKind = akAddFeature(arg->argKind, akbVariable);
  618.  
  619.     /* akbIndefinite means inline or out-of-line */
  620.  
  621.     if (it->itIndefinite)
  622.         arg->argKind = akAddFeature(arg->argKind, akbIndefinite);
  623.     }
  624.  
  625.     /*
  626.      *    Kernel servers can't do quick-checking of request arguments
  627.      *    which are out-of-line or ports, because the deallocate bit isn't
  628.      *    predictable.  This is because the deallocate bit is preserved
  629.      *    at message copyin time and normalized during message copyout.
  630.      *    This accomodates old IPC programs which expect the deallocate
  631.      *    bit to be preserved.
  632.      */
  633.  
  634.     if (akCheck(arg->argKind, akbRequest) &&
  635.     !arg->argLongForm &&
  636.     (it->itOutName != MACH_MSG_TYPE_POLYMORPHIC) &&
  637.     !it->itVarArray &&
  638.     !(IsKernelServer && (!it->itInLine ||
  639.                  MACH_MSG_TYPE_PORT_ANY(it->itOutName))))
  640.     arg->argKind = akAddFeature(arg->argKind, akbRequestQC);
  641.  
  642.     if (akCheck(arg->argKind, akbReply) &&
  643.     !arg->argLongForm &&
  644.     (it->itOutName != MACH_MSG_TYPE_POLYMORPHIC) &&
  645.     !it->itVarArray)
  646.     arg->argKind = akAddFeature(arg->argKind, akbReplyQC);
  647.  
  648.     /*
  649.      * Need to use a local variable in the following cases:
  650.      *    1) There is a translate-out function & the argument is being
  651.      *       returned.  We need to translate it before it hits the message.
  652.      *    2) There is a translate-in function & the argument is
  653.      *       sent and returned.  We need a local variable for its address.
  654.      *    3) There is a destructor function, which will be used
  655.      *       (SendRcv and not ReturnSnd), and there is a translate-in
  656.      *       function whose value must be saved for the destructor.
  657.      *    4) This is a count arg, getting returned.  The count can't get
  658.      *       stored directly into the msg-type, because the msg-type won't
  659.      *       get initialized until later, and that would trash the count.
  660.      *    5) This is a poly arg, getting returned.  The name can't get
  661.      *       stored directly into the msg-type, because the msg-type won't
  662.      *       get initialized until later, and that would trash the name.
  663.      *  6) This is a dealloc arg, being returned.  The name can't be
  664.      *       stored directly into the msg_type, because the msg-type
  665.      *       field is a bit-field.
  666.      */
  667.  
  668.     if (((it->itOutTrans != strNULL) &&
  669.      akCheck(arg->argKind, akbReturnSnd)) ||
  670.     ((it->itInTrans != strNULL) &&
  671.      akCheckAll(arg->argKind, akbSendRcv|akbReturnSnd)) ||
  672.     ((it->itDestructor != strNULL) &&
  673.      akCheck(arg->argKind, akbSendRcv) &&
  674.      !akCheck(arg->argKind, akbReturnSnd) &&
  675.      (it->itInTrans != strNULL)) ||
  676.     ((akIdent(arg->argKind) == akeCount) &&
  677.      akCheck(arg->argKind, akbReturnSnd)) ||
  678.     ((akIdent(arg->argKind) == akePoly) &&
  679.      akCheck(arg->argKind, akbReturnSnd)) ||
  680.     ((akIdent(arg->argKind) == akeDealloc) &&
  681.      akCheck(arg->argKind, akbReturnSnd)))
  682.     {
  683.     arg->argKind = akRemFeature(arg->argKind, akbReplyCopy);
  684.     arg->argKind = akAddFeature(arg->argKind, akbVarNeeded);
  685.     }
  686.  
  687.     /*
  688.      * If the argument is a variable-length array that can be passed in-line
  689.      * or out-of-line, and is being returned, the server procedure
  690.      * is passed a pointer to the buffer, which it can change.
  691.      */
  692.     if (it->itIndefinite &&
  693.     akCheck(arg->argKind, akbReturnSnd))
  694.     {
  695.     arg->argKind = akAddFeature(arg->argKind, akbPointer);
  696.     }
  697. }
  698.  
  699. /* arg->argType may be NULL in this function */
  700.  
  701. static void
  702. rtCheckRoutineArg(rt, arg)
  703.     routine_t *rt;
  704.     argument_t *arg;
  705. {
  706.     switch (akIdent(arg->argKind))
  707.     {
  708.       case akeRequestPort:
  709.     if (rt->rtRequestPort != argNULL)
  710.         warn("multiple RequestPort args in %s; %s won't be used",
  711.          rt->rtName, rt->rtRequestPort->argName);
  712.     rt->rtRequestPort = arg;
  713.     break;
  714.  
  715.       case akeReplyPort:
  716.     if (rt->rtReplyPort != argNULL)
  717.         warn("multiple ReplyPort args in %s; %s won't be used",
  718.          rt->rtName, rt->rtReplyPort->argName);
  719.     rt->rtReplyPort = arg;
  720.     break;
  721.  
  722.       case akeWaitTime:
  723.     if (rt->rtWaitTime != argNULL)
  724.         warn("multiple WaitTime args in %s; %s won't be used",
  725.          rt->rtName, rt->rtWaitTime->argName);
  726.     rt->rtWaitTime = arg;
  727.     break;
  728.  
  729.       case akeMsgOption:
  730.     if (rt->rtMsgOption != argNULL)
  731.         warn("multiple MsgOption args in %s; %s won't be used",
  732.          rt->rtName, rt->rtMsgOption->argName);
  733.     rt->rtMsgOption = arg;
  734.     break;
  735.  
  736.       case akeMsgSeqno:
  737.     if (rt->rtMsgSeqno != argNULL)
  738.         warn("multiple MsgSeqno args in %s; %s won't be used",
  739.          rt->rtName, rt->rtMsgSeqno->argName);
  740.     rt->rtMsgSeqno = arg;
  741.     break;
  742.  
  743.       case akeReturn:
  744.     if (rt->rtReturn != argNULL)
  745.         warn("multiple Return args in %s; %s won't be used",
  746.          rt->rtName, rt->rtReturn->argName);
  747.     rt->rtReturn = arg;
  748.     break;
  749.  
  750.       default:
  751.     break;
  752.     }
  753. }
  754.  
  755. /* arg->argType may be NULL in this function */
  756.  
  757. static void
  758. rtSetArgDefaults(rt, arg)
  759.     routine_t *rt;
  760.     register argument_t *arg;
  761. {
  762.     arg->argRoutine = rt;
  763.     if (arg->argVarName == strNULL)
  764.     arg->argVarName = arg->argName;
  765.     if (arg->argMsgField == strNULL)
  766.     switch(akIdent(arg->argKind))
  767.     {
  768.       case akeRequestPort:
  769.         arg->argMsgField = "Head.msgh_request_port";
  770.         break;
  771.       case akeReplyPort:
  772.         arg->argMsgField = "Head.msgh_reply_port";
  773.         break;
  774.       case akeMsgSeqno:
  775.         arg->argMsgField = "Head.msgh_seqno";
  776.         break;
  777.       default:
  778.         arg->argMsgField = arg->argName;
  779.         break;
  780.     }
  781.     if (arg->argTTName == strNULL)
  782.     arg->argTTName = strconcat(arg->argName, "Type");
  783.     if (arg->argPadName == strNULL)
  784.     arg->argPadName = strconcat(arg->argName, "Pad");
  785.  
  786.     /*
  787.      *    The poly args for the request and reply ports have special defaults,
  788.      *    because their msg-type-name values aren't stored in normal fields.
  789.      */
  790.  
  791.     if ((rt->rtRequestPort != argNULL) &&
  792.     (rt->rtRequestPort->argPoly == arg) &&
  793.     (arg->argType != itNULL)) {
  794.     arg->argMsgField = "Head.msgh_bits";
  795.     arg->argType->itInTrans = "MACH_MSGH_BITS_REQUEST";
  796.     }
  797.  
  798.     if ((rt->rtReplyPort != argNULL) &&
  799.     (rt->rtReplyPort->argPoly == arg) &&
  800.     (arg->argType != itNULL)) {
  801.     arg->argMsgField = "Head.msgh_bits";
  802.     arg->argType->itInTrans = "MACH_MSGH_BITS_REPLY";
  803.     }
  804. }
  805.  
  806. static void
  807. rtAddCountArg(arg)
  808.     register argument_t *arg;
  809. {
  810.     register argument_t *count;
  811.  
  812.     count = argAlloc();
  813.     count->argName = strconcat(arg->argName, "Cnt");
  814.     count->argType = itMakeCountType();
  815.     count->argParent = arg;
  816.     count->argMultiplier = arg->argType->itElement->itNumber;
  817.     count->argNext = arg->argNext;
  818.     arg->argNext = count;
  819.     arg->argCount = count;
  820.  
  821.     if (arg->argType->itString) {
  822.     /* C String gets no Count argument on either side.
  823.        There is no explicit field in the message -
  824.        the count is passed as part of the descriptor. */
  825.     count->argKind = akeCount;
  826.     count->argVarName = (char *)0;
  827.     } else
  828.     count->argKind = akAddFeature(akCount,
  829.                   akCheck(arg->argKind, akbSendReturnBits));
  830.  
  831.     if (arg->argLongForm)
  832.     count->argMsgField = strconcat(arg->argTTName,
  833.                        ".msgtl_number");
  834.     else
  835.     count->argMsgField = strconcat(arg->argTTName, ".msgt_number");
  836. }
  837.  
  838. static void
  839. rtAddCountInOutArg(arg)
  840.     register argument_t *arg;
  841. {
  842.     register argument_t *count;
  843.  
  844.     /*
  845.      *    The user sees a single count variable.  However, to get the
  846.      *    count passed from user to server for variable-sized inline OUT
  847.      *    arrays, we need two count arguments internally.  This is
  848.      *    because the count value lives in different message fields (and
  849.      *    is scaled differently) in the request and reply messages.
  850.      *
  851.      *    The two variables have the same name to simplify code generation.
  852.      *
  853.      *    This variable has a null argParent field because it has akbRequest.
  854.      *    For example, see rtCheckVariable.
  855.      */
  856.  
  857.     count = argAlloc();
  858.     count->argName = strconcat(arg->argName, "Cnt");
  859.     count->argType = itMakeCountType();
  860.     count->argParent = argNULL;
  861.     count->argNext = arg->argNext;
  862.     arg->argNext = count;
  863.     (count->argCInOut = arg->argCount)->argCInOut = count;
  864.     count->argKind = akCountInOut;
  865. }
  866.  
  867. static void
  868. rtAddPolyArg(arg)
  869.     register argument_t *arg;
  870. {
  871.     register ipc_type_t *it = arg->argType;
  872.     register argument_t *poly;
  873.     arg_kind_t akbsend, akbreturn;
  874.  
  875.     poly = argAlloc();
  876.     poly->argName = strconcat(arg->argName, "Poly");
  877.     poly->argType = itMakePolyType();
  878.     poly->argParent = arg;
  879.     poly->argNext = arg->argNext;
  880.     arg->argNext = poly;
  881.     arg->argPoly = poly;
  882.  
  883.     /*
  884.      * akbsend is bits added if the arg is In;
  885.      * akbreturn is bits added if the arg is Out.
  886.      * The mysterious business with KernelServer subsystems:
  887.      * when packing Out arguments, they use OutNames instead
  888.      * of InNames, and the OutName determines if they are poly-in
  889.      * as well as poly-out.
  890.      */
  891.  
  892.     akbsend = akbSend|akbSendBody;
  893.     akbreturn = akbReturn|akbReturnBody;
  894.  
  895.     if (it->itInName == MACH_MSG_TYPE_POLYMORPHIC)
  896.     {
  897.     akbsend |= akbUserArg|akbSendSnd;
  898.     if (!IsKernelServer)
  899.         akbreturn |= akbServerArg|akbReturnSnd;
  900.     }
  901.     if (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)
  902.     {
  903.     akbsend |= akbServerArg|akbSendRcv;
  904.     akbreturn |= akbUserArg|akbReturnRcv;
  905.     if (IsKernelServer)
  906.         akbreturn |= akbServerArg|akbReturnSnd;
  907.     }
  908.  
  909.     poly->argKind = akPoly;
  910.     if (akCheck(arg->argKind, akbSend))
  911.     poly->argKind = akAddFeature(poly->argKind,
  912.                      akCheck(arg->argKind, akbsend));
  913.     if (akCheck(arg->argKind, akbReturn))
  914.     poly->argKind = akAddFeature(poly->argKind,
  915.                      akCheck(arg->argKind, akbreturn));
  916.  
  917.     if (arg->argLongForm)
  918.     poly->argMsgField = strconcat(arg->argTTName,
  919.                       ".msgtl_name");
  920.     else
  921.     poly->argMsgField = strconcat(arg->argTTName, ".msgt_name");
  922. }
  923.  
  924. static void
  925. rtAddDeallocArg(arg)
  926.     register argument_t *arg;
  927. {
  928.     register argument_t *dealloc;
  929.  
  930.     dealloc = argAlloc();
  931.     dealloc->argName = strconcat(arg->argName, "Dealloc");
  932.     dealloc->argType = itMakeDeallocType();
  933.     dealloc->argParent = arg;
  934.     dealloc->argNext = arg->argNext;
  935.     arg->argNext = dealloc;
  936.     arg->argDealloc = dealloc;
  937.  
  938.     /*
  939.      *    For Indefinite types, we leave out akbSendSnd and akbReturnSnd
  940.      *    so that the normal argument-packing is bypassed.  The special code
  941.      *    generated for the Indefinite argument handles the deallocate bit.
  942.      *    (It can only be enabled if the data is actually out-of-line.)
  943.      */
  944.  
  945.     dealloc->argKind = akeDealloc;
  946.     if (akCheck(arg->argKind, akbSend))
  947.     dealloc->argKind = akAddFeature(dealloc->argKind,
  948.         akCheck(arg->argKind,
  949.             akbUserArg|akbSend|akbSendBody|
  950.             (arg->argType->itIndefinite ? 0 : akbSendSnd)));
  951.     if (akCheck(arg->argKind, akbReturn)) {
  952.     dealloc->argKind = akAddFeature(dealloc->argKind,
  953.         akCheck(arg->argKind,
  954.             akbServerArg|akbReturn|akbReturnBody|
  955.             (arg->argType->itIndefinite ? 0 : akbReturnSnd)));
  956.  
  957.     /*
  958.      *  Without akbReturnSnd, rtAugmentArgKind will not add
  959.      *  akbVarNeeded and rtAddByReference will not set
  960.      *  argByReferenceServer.  So we do it here.
  961.      */
  962.  
  963.     if (arg->argType->itIndefinite) {
  964.         dealloc->argKind = akAddFeature(dealloc->argKind, akbVarNeeded);
  965.         dealloc->argByReferenceServer = TRUE;
  966.     }
  967.     }
  968.  
  969.     if (arg->argLongForm)
  970.     dealloc->argMsgField = strconcat(arg->argTTName,
  971.                      ".msgtl_header.msgt_deallocate");
  972.     else
  973.     dealloc->argMsgField = strconcat(arg->argTTName, ".msgt_deallocate");
  974.  
  975. }
  976.  
  977. static void
  978. rtAddSCopyArg(arg)
  979.     register argument_t *arg;
  980. {
  981.     register argument_t *scopy;
  982.  
  983.     scopy = argAlloc();
  984.     scopy->argName = strconcat(arg->argName, "SCopy");
  985.     scopy->argType = itMakeDeallocType();
  986.     scopy->argParent = arg;
  987.     scopy->argNext = arg->argNext;
  988.     arg->argNext = scopy;
  989.     arg->argSCopy = scopy;
  990.  
  991.     scopy->argKind = akServerCopy;
  992.  
  993.     if (arg->argLongForm)
  994.     scopy->argMsgField = strconcat(arg->argTTName,
  995.                     ".msgtl_header.msgt_inline");
  996.     else
  997.     scopy->argMsgField = strconcat(arg->argTTName, ".msgt_inline");
  998. }
  999.  
  1000. static void
  1001. rtCheckRoutineArgs(rt)
  1002.     routine_t *rt;
  1003. {
  1004.     register argument_t *arg;
  1005.  
  1006.     for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
  1007.     {
  1008.     register ipc_type_t *it = arg->argType;
  1009.  
  1010.     rtDefaultArgKind(rt, arg);
  1011.     rtCheckRoutineArg(rt, arg);
  1012.  
  1013.     /* need to set argTTName before adding implicit args */
  1014.     rtSetArgDefaults(rt, arg);
  1015.  
  1016.     /* the arg may not have a type (if there was some error in parsing it),
  1017.        in which case we don't want to do these steps. */
  1018.  
  1019.     if (it != itNULL)
  1020.     {
  1021.         /* need to set argLongForm before adding implicit args */
  1022.         rtProcessArgFlags(arg);
  1023.         rtAugmentArgKind(arg);
  1024.  
  1025.         /* args added here will get processed in later iterations */
  1026.         /* order of args is 'arg poly countinout count dealloc scopy' */
  1027.  
  1028.         if (arg->argServerCopy)
  1029.         rtAddSCopyArg(arg);
  1030.         if (arg->argDeallocate == d_MAYBE)
  1031.         rtAddDeallocArg(arg);
  1032.         if (it->itVarArray)
  1033.         rtAddCountArg(arg);
  1034.         if (arg->argCountInOut)
  1035.         rtAddCountInOutArg(arg);
  1036.         if ((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) ||
  1037.         (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC))
  1038.         rtAddPolyArg(arg);
  1039.     }
  1040.     }
  1041. }
  1042.  
  1043. static void
  1044. rtCheckArgTypes(rt)
  1045.     routine_t *rt;
  1046. {
  1047.     if (rt->rtRequestPort == argNULL)
  1048.     error("%s %s doesn't have a server port argument",
  1049.           rtRoutineKindToStr(rt->rtKind), rt->rtName);
  1050.  
  1051.     if ((rt->rtKind == rkFunction) &&
  1052.     (rt->rtReturn == argNULL))
  1053.     error("Function %s doesn't have a return arg", rt->rtName);
  1054.  
  1055.     if ((rt->rtKind != rkFunction) &&
  1056.     (rt->rtReturn != argNULL))
  1057.     error("non-function %s has a return arg", rt->rtName);
  1058.  
  1059.     if ((rt->rtReturn == argNULL) && !rt->rtProcedure)
  1060.     rt->rtReturn = rt->rtRetCode;
  1061.  
  1062.     rt->rtServerReturn = rt->rtReturn;
  1063.  
  1064.     if ((rt->rtReturn != argNULL) &&
  1065.     (rt->rtReturn->argType != itNULL))
  1066.     itCheckReturnType(rt->rtReturn->argName,
  1067.               rt->rtReturn->argType);
  1068.  
  1069.     if ((rt->rtRequestPort != argNULL) &&
  1070.     (rt->rtRequestPort->argType != itNULL))
  1071.     itCheckRequestPortType(rt->rtRequestPort->argName,
  1072.                    rt->rtRequestPort->argType);
  1073.  
  1074.     if ((rt->rtReplyPort != argNULL) &&
  1075.     (rt->rtReplyPort->argType != itNULL))
  1076.     itCheckReplyPortType(rt->rtReplyPort->argName,
  1077.                  rt->rtReplyPort->argType);
  1078.  
  1079.     if ((rt->rtWaitTime != argNULL) &&
  1080.     (rt->rtWaitTime->argType != itNULL))
  1081.     itCheckIntType(rt->rtWaitTime->argName,
  1082.                rt->rtWaitTime->argType);
  1083.  
  1084.     if ((rt->rtMsgOption != argNULL) &&
  1085.     (rt->rtMsgOption->argType != itNULL))
  1086.     itCheckIntType(rt->rtMsgOption->argName,
  1087.                rt->rtMsgOption->argType);
  1088.  
  1089.     if ((rt->rtMsgSeqno != argNULL) &&
  1090.     (rt->rtMsgSeqno->argType != itNULL))
  1091.     itCheckIntType(rt->rtMsgSeqno->argName,
  1092.                rt->rtMsgSeqno->argType);
  1093. }
  1094.  
  1095. /*
  1096.  * Check for arguments which are missing seemingly needed functions.
  1097.  * We make this check here instead of in itCheckDecl, because here
  1098.  * we can take into account what kind of argument the type is
  1099.  * being used with.
  1100.  *
  1101.  * These are warnings, not hard errors, because mig will generate
  1102.  * reasonable code in any case.  The generated code will work fine
  1103.  * if the ServerType and TransType are really the same, even though
  1104.  * they have different names.
  1105.  */
  1106.  
  1107. static void
  1108. rtCheckArgTrans(rt)
  1109.     routine_t *rt;
  1110. {
  1111.     register argument_t *arg;
  1112.  
  1113.     /* the arg may not have a type (if there was some error in parsing it) */
  1114.  
  1115.     for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
  1116.     {
  1117.     register ipc_type_t *it = arg->argType;
  1118.  
  1119.     if ((it != itNULL) &&
  1120.         !streql(it->itServerType, it->itTransType))
  1121.     {
  1122.         if (akCheck(arg->argKind, akbSendRcv) &&
  1123.         (it->itInTrans == strNULL))
  1124.         warn("%s: argument has no in-translation function",
  1125.              arg->argName);
  1126.  
  1127.         if (akCheck(arg->argKind, akbReturnSnd) &&
  1128.         (it->itOutTrans == strNULL))
  1129.         warn("%s: argument has no out-translation function",
  1130.              arg->argName);
  1131.     }
  1132.     }
  1133. }
  1134.  
  1135. /*
  1136.  * Adds an implicit return-code argument.  It exists in the reply message,
  1137.  * where it is the first piece of data.  Even if there is no reply
  1138.  * message (rtOneWay is true), we generate the argument because
  1139.  * the server-side stub needs a dummy reply msg to return error codes
  1140.  * back to the server loop.
  1141.  */
  1142.  
  1143. static void
  1144. rtAddRetCode(rt)
  1145.     routine_t *rt;
  1146. {
  1147.     register argument_t *arg = argAlloc();
  1148.  
  1149.     arg->argName = "RetCode";
  1150.     arg->argType = itRetCodeType;
  1151.     arg->argKind = akRetCode;
  1152.     rt->rtRetCode = arg;
  1153.  
  1154.     /* add at beginning, so return-code is first in the reply message  */
  1155.     arg->argNext = rt->rtArgs;
  1156.     rt->rtArgs = arg;
  1157. }
  1158.  
  1159. /*
  1160.  *  Adds a dummy WaitTime argument to the function.
  1161.  *  This argument doesn't show up in any C argument lists;
  1162.  *  it implements the global WaitTime statement.
  1163.  */
  1164.  
  1165. static void
  1166. rtAddWaitTime(rt, name)
  1167.     routine_t *rt;
  1168.     identifier_t name;
  1169. {
  1170.     register argument_t *arg = argAlloc();
  1171.     argument_t **loc;
  1172.  
  1173.     arg->argName = "dummy WaitTime arg";
  1174.     arg->argVarName = name;
  1175.     arg->argType = itWaitTimeType;
  1176.     arg->argKind = akeWaitTime;
  1177.     rt->rtWaitTime = arg;
  1178.  
  1179.     /* add wait-time after msg-option, if possible */
  1180.  
  1181.     if (rt->rtMsgOption != argNULL)
  1182.     loc = &rt->rtMsgOption->argNext;
  1183.     else
  1184.     loc = &rt->rtArgs;
  1185.  
  1186.     arg->argNext = *loc;
  1187.     *loc = arg;
  1188.  
  1189.     rtSetArgDefaults(rt, arg);
  1190. }
  1191.  
  1192. /*
  1193.  *  Adds a dummy MsgOption argument to the function.
  1194.  *  This argument doesn't show up in any C argument lists;
  1195.  *  it implements the global MsgOption statement.
  1196.  */
  1197.  
  1198. static void
  1199. rtAddMsgOption(rt, name)
  1200.     routine_t *rt;
  1201.     identifier_t name;
  1202. {
  1203.     register argument_t *arg = argAlloc();
  1204.     argument_t **loc;
  1205.  
  1206.     arg->argName = "dummy MsgOption arg";
  1207.     arg->argVarName = name;
  1208.     arg->argType = itMsgOptionType;
  1209.     arg->argKind = akeMsgOption;
  1210.     rt->rtMsgOption = arg;
  1211.  
  1212.     /* add msg-option after msg-seqno */
  1213.  
  1214.     if (rt->rtMsgSeqno != argNULL)
  1215.     loc = &rt->rtMsgSeqno->argNext;
  1216.     else
  1217.     loc = &rt->rtArgs;
  1218.  
  1219.     arg->argNext = *loc;
  1220.     *loc = arg;
  1221.  
  1222.     rtSetArgDefaults(rt, arg);
  1223. }
  1224.  
  1225. /*
  1226.  *  Adds a dummy reply port argument to the function.
  1227.  */
  1228.  
  1229. static void
  1230. rtAddDummyReplyPort(rt, type)
  1231.     routine_t *rt;
  1232.     ipc_type_t *type;
  1233. {
  1234.     register argument_t *arg = argAlloc();
  1235.     argument_t **loc;
  1236.  
  1237.     arg->argName = "dummy ReplyPort arg";
  1238.     arg->argVarName = "dummy ReplyPort arg";
  1239.     arg->argType = type;
  1240.     arg->argKind = akeReplyPort;
  1241.     rt->rtReplyPort = arg;
  1242.  
  1243.     /* add the reply port after the request port */
  1244.  
  1245.     if (rt->rtRequestPort != argNULL)
  1246.     loc = &rt->rtRequestPort->argNext;
  1247.     else
  1248.     loc = &rt->rtArgs;
  1249.  
  1250.     arg->argNext = *loc;
  1251.     *loc = arg;
  1252.  
  1253.     rtSetArgDefaults(rt, arg);
  1254. }
  1255.  
  1256. /*
  1257.  * Initializes argRequestPos, argReplyPos, rtMaxRequestPos, rtMaxReplyPos,
  1258.  * rtNumRequestVar, rtNumReplyVar, and adds akbVarNeeded to those arguments
  1259.  * that need it because of variable-sized inline considerations.
  1260.  *
  1261.  * argRequestPos and argReplyPos get -1 if the value shouldn't be used.
  1262.  */
  1263. static void
  1264. rtCheckVariable(rt)
  1265.     register routine_t *rt;
  1266. {
  1267.     register argument_t *arg;
  1268.     int NumRequestVar = 0;
  1269.     int NumReplyVar = 0;
  1270.     int MaxRequestPos;
  1271.     int MaxReplyPos;
  1272.  
  1273.     for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
  1274.     register argument_t *parent = arg->argParent;
  1275.  
  1276.     if (parent == argNULL) {
  1277.         if (akCheck(arg->argKind, akbRequest|akbSend)) {
  1278.         arg->argRequestPos = NumRequestVar;
  1279.         MaxRequestPos = NumRequestVar;
  1280.         if (akCheck(arg->argKind, akbVariable))
  1281.             NumRequestVar++;
  1282.         } else
  1283.         arg->argRequestPos = -1;
  1284.  
  1285.         if (akCheck(arg->argKind, akbReply|akbReturn)) {
  1286.         arg->argReplyPos = NumReplyVar;
  1287.         MaxReplyPos = NumReplyVar;
  1288.         if (akCheck(arg->argKind, akbVariable))
  1289.             NumReplyVar++;
  1290.         } else
  1291.         arg->argReplyPos = -1;
  1292.     } else {
  1293.         arg->argRequestPos = parent->argRequestPos;
  1294.         arg->argReplyPos = parent->argReplyPos;
  1295.     }
  1296.  
  1297.     /* Out variables that follow a variable-sized field
  1298.        need VarNeeded or ReplyCopy; they can't be stored
  1299.        directly into the reply message. */
  1300.  
  1301.     if (akCheck(arg->argKind, akbReturnSnd) &&
  1302.         !akCheck(arg->argKind, akbReplyCopy|akbVarNeeded) &&
  1303.         (arg->argReplyPos > 0))
  1304.         arg->argKind = akAddFeature(arg->argKind, akbVarNeeded);
  1305.     }
  1306.  
  1307.     rt->rtNumRequestVar = NumRequestVar;
  1308.     rt->rtNumReplyVar = NumReplyVar;
  1309.     rt->rtMaxRequestPos = MaxRequestPos;
  1310.     rt->rtMaxReplyPos = MaxReplyPos;
  1311. }
  1312.  
  1313. /*
  1314.  * Adds akbDestroy where needed.
  1315.  */
  1316.  
  1317. static void
  1318. rtCheckDestroy(rt)
  1319.     register routine_t *rt;
  1320. {
  1321.     register argument_t *arg;
  1322.  
  1323.     for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
  1324.     register ipc_type_t *it = arg->argType;
  1325.  
  1326.     if(akCheck(arg->argKind, akbSendRcv) &&
  1327.        !akCheck(arg->argKind, akbReturnSnd)) {
  1328.        if ((it->itDestructor != strNULL) ||
  1329.            (akCheck(arg->argKind, akbIndefinite) && !arg->argServerCopy))
  1330.         arg->argKind = akAddFeature(arg->argKind, akbDestroy);
  1331.     }
  1332.     }
  1333. }
  1334.  
  1335. /*
  1336.  * Sets ByReferenceUser and ByReferenceServer.
  1337.  */
  1338.  
  1339. static void
  1340. rtAddByReference(rt)
  1341.     register routine_t *rt;
  1342. {
  1343.     register argument_t *arg;
  1344.  
  1345.     for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
  1346.     register ipc_type_t *it = arg->argType;
  1347.  
  1348.     if (akCheck(arg->argKind, akbReturnRcv) &&
  1349.         (it->itStruct || it->itIndefinite)) {
  1350.         arg->argByReferenceUser = TRUE;
  1351.  
  1352.         /*
  1353.          *    A CountInOut arg itself is not akbReturnRcv,
  1354.          *    so we need to set argByReferenceUser specially.
  1355.          */
  1356.  
  1357.         if (arg->argCInOut != argNULL)
  1358.         arg->argCInOut->argByReferenceUser = TRUE;
  1359.     }
  1360.  
  1361.     if (akCheck(arg->argKind, akbReturnSnd) &&
  1362.         (it->itStruct || it->itIndefinite))
  1363.         arg->argByReferenceServer = TRUE;
  1364.     }
  1365. }
  1366.  
  1367. void
  1368. rtCheckRoutine(rt)
  1369.     register routine_t *rt;
  1370. {
  1371.     /* Initialize random fields. */
  1372.  
  1373.     rt->rtErrorName = ErrorProc;
  1374.     rt->rtOneWay = ((rt->rtKind == rkSimpleProcedure) ||
  1375.             (rt->rtKind == rkSimpleRoutine));
  1376.     rt->rtProcedure = ((rt->rtKind == rkProcedure) ||
  1377.                (rt->rtKind == rkSimpleProcedure));
  1378.     rt->rtUseError = rt->rtProcedure || (rt->rtKind == rkFunction);
  1379.     rt->rtServerName = strconcat(ServerPrefix, rt->rtName);
  1380.     rt->rtUserName = strconcat(UserPrefix, rt->rtName);
  1381.  
  1382.     /* Add implicit arguments. */
  1383.  
  1384.     rtAddRetCode(rt);
  1385.  
  1386.     /* Check out the arguments and their types.  Add count, poly
  1387.        implicit args.  Any arguments added after rtCheckRoutineArgs
  1388.        should have rtSetArgDefaults called on them. */
  1389.  
  1390.     rtCheckRoutineArgs(rt);
  1391.  
  1392.     /* Add dummy WaitTime and MsgOption arguments, if the routine
  1393.        doesn't have its own args and the user specified global values. */
  1394.  
  1395.     if (rt->rtReplyPort == argNULL)
  1396.     if (rt->rtOneWay)
  1397.         rtAddDummyReplyPort(rt, itZeroReplyPortType);
  1398.     else
  1399.         rtAddDummyReplyPort(rt, itRealReplyPortType);
  1400.  
  1401.     if (rt->rtMsgOption == argNULL)
  1402.     if (MsgOption == strNULL)
  1403.         rtAddMsgOption(rt, "MACH_MSG_OPTION_NONE");
  1404.     else
  1405.         rtAddMsgOption(rt, MsgOption);
  1406.  
  1407.     if ((rt->rtWaitTime == argNULL) &&
  1408.     (WaitTime != strNULL))
  1409.     rtAddWaitTime(rt, WaitTime);
  1410.  
  1411.     /* Now that all the arguments are in place, do more checking. */
  1412.  
  1413.     rtCheckArgTypes(rt);
  1414.     rtCheckArgTrans(rt);
  1415.  
  1416.     if (rt->rtOneWay && rtCheckMask(rt->rtArgs, akbReturn))
  1417.     error("%s %s has OUT argument",
  1418.           rtRoutineKindToStr(rt->rtKind), rt->rtName);
  1419.  
  1420.     /* If there were any errors, don't bother calculating more info
  1421.        that is only used in code generation anyway.  Therefore,
  1422.        the following functions don't have to worry about null types. */
  1423.  
  1424.     if (errors > 0)
  1425.     return;
  1426.  
  1427.     rtCheckSimpleIn(rt->rtArgs, akbRequest,
  1428.             &rt->rtSimpleFixedRequest,
  1429.             &rt->rtSimpleSendRequest);
  1430.     rtCheckSimpleOut(rt->rtArgs, akbRequest,
  1431.              &rt->rtSimpleCheckRequest,
  1432.              &rt->rtSimpleReceiveRequest);
  1433.     rt->rtRequestSize = rtFindSize(rt->rtArgs, akbRequest);
  1434.  
  1435.     if (IsKernelServer)
  1436.     rtCheckSimpleOut(rt->rtArgs, akbReply,
  1437.              &rt->rtSimpleFixedReply,
  1438.              &rt->rtSimpleSendReply);
  1439.     else
  1440.     rtCheckSimpleIn(rt->rtArgs, akbReply,
  1441.             &rt->rtSimpleFixedReply,
  1442.             &rt->rtSimpleSendReply);
  1443.     rtCheckSimpleOut(rt->rtArgs, akbReply,
  1444.              &rt->rtSimpleCheckReply,
  1445.              &rt->rtSimpleReceiveReply);
  1446.     rt->rtReplySize = rtFindSize(rt->rtArgs, akbReply);
  1447.  
  1448.     rtCheckVariable(rt);
  1449.     rtCheckDestroy(rt);
  1450.     rtAddByReference(rt);
  1451.  
  1452.     if (rt->rtKind == rkFunction)
  1453.     rt->rtNoReplyArgs = FALSE;
  1454.     else
  1455.     rt->rtNoReplyArgs = !rtCheckMask(rt->rtArgs, akbReturnSnd);
  1456. }
  1457.